#include "DownloadThread.h"




/****
//define the download function for the youtube service
*/
int libvdn_DownloadYoutube(const char* url, const char* filename, libvdnEvent& evt, wxWindow* par);


/****
//the function that will write the video file 
*/

static size_t libvdn_writer(void *buffer, size_t size, size_t nmemb, void *stream)
	{
		 struct libvdn_vidFile *out = (struct libvdn_vidFile *)stream;

		if(out && !out->stream)
			{
			out->stream=fopen(out->filename,"wb");
				if(!out->stream)
					return -2;
			}
		return fwrite(buffer,size,nmemb,out->stream);
	}

/****
//progress function 
*/
static int progress_callback(libvdnEvent* evt,double t,double d,double ultotal,double ulnow)
	{
	//t is the total file size
	//d is what has been downloaded so far
	
	//method: set a param in the event with the percent of the file that has
// been downloaded so far.  send the event every time and the progress bar will
//be updated accordingly
	int percentDone = (int)((d/t)*100);

	evt->SetDownloadStatus(libvdnEvent::DOWNLOAD_INPROGRESS);
		

	//check that t and d are > 0 and store the values in the event
	if(t>0 && d >= 0)
		{
		evt->SetDownloadedBytes((int)d);
		evt->SetTotalBytes((int)t);
		}



		//make sure the percent we're passing to the progress bar is 
		//within the acceptable range
		if(percentDone >= 0 && percentDone < 100)
			{
		evt->SetDownloadedPercent(percentDone);
			}
		else 
			{
			if(percentDone < 0)
				{
				percentDone = 0;
				evt->SetDownloadedPercent(percentDone);
				}
			if(percentDone > 100)
				{
				percentDone = 100;
				evt->SetDownloadedPercent(percentDone);
				}
			if(percentDone == 100)
				{
				evt->SetDownloadedPercent(percentDone);
				}
			}

		if( evt->GetParentWindow() )
			{
		evt->GetParentWindow()->GetEventHandler()->AddPendingEvent(*evt);
			}
		
		wxASSERT_MSG(evt->GetParentWindow(),wxT("Could not retrieve parent window."));

		 

	if(percentDone == 100)
		{
		evt->SetDownloadStatus(libvdnEvent::DOWNLOAD_COMPLETE);
		if(evt->GetParentWindow())
			{
			evt->GetParentWindow()->GetEventHandler()->AddPendingEvent(*evt);
			}
		}

	return 0;
	}



	



/****
//routes all of the services to the right functions
//returns true for a success, false for a failure
*/
int libvdn_DownloadVideo(libvdn_SERVICE service, const char* url, const char* filename, libvdnEvent& evt, wxWindow* par)
	{
		
	
	if(service == SER_YOUTUBE)
		{
#ifdef MYDEBUG
		wxMessageBox(wxT("In DownloadVideo, url = ") + wxString::FromAscii(url));
#endif
		int SuccessOrFail = libvdn_DownloadYoutube(url, filename,evt, par);
			return SuccessOrFail;
		}
		else
		{
			return -1; //the only service initially supported is youtube
		} 

	
	}


/****
//Downloader for the youtube service
*/

int libvdn_DownloadYoutube(const char* url, const char* filename, libvdnEvent& evt, wxWindow* par)
	{


	CURL *curl = curl_easy_init();
	CURLcode ret;

	
	//set the url
	ret = curl_easy_setopt(curl, CURLOPT_URL, url);
#ifdef MYDEBUG
	wxMessageBox(wxT("In DownloadYoutube, url = ") + wxString::FromAscii(url));
#endif
	if(ret != CURLE_OK)
		{
			
			return ret;
		};

	struct libvdn_vidFile vid={
		(const char*)filename,
		NULL
		};

	//set the write function to write data to harddisk
	ret = curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,libvdn_writer);
	if(ret != CURLE_OK)
		{
		
		return ret;
		}
	//set the struct where the data will be stored
	ret = curl_easy_setopt(curl,CURLOPT_WRITEDATA, &vid);
	if(ret != CURLE_OK)
		{
		
		return ret;
		}

	
	//for DEBUG only
	curl_easy_setopt(curl,CURLOPT_VERBOSE,1L); //output everything to the debugout file
	//*****************

	//make sure that libcurl follows the redirects to the video
	curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1);
	curl_easy_setopt(curl,CURLOPT_AUTOREFERER,1);


	//set the headers (User-Agent, etc)...the "Accept" header is crucial to being able to download the video
	struct curl_slist *headers = NULL;

	headers = curl_slist_append(headers, "User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1");
	headers = curl_slist_append(headers, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
	
	curl_easy_setopt(headers,CURLOPT_HTTPHEADER, headers);

	//set the values so that curl will update us on our progress
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION,progress_callback);
	curl_easy_setopt(curl,CURLOPT_PROGRESSDATA, &evt);
	
	evt.SetParentWindow(par);

		//download the video :-)
		ret = curl_easy_perform(curl);
		if(ret != CURLE_OK)
		{
		
		return ret;
		}

		curl_easy_cleanup(curl);

	//make sure the .flv file is closed at the end
	
	if(vid.stream)
		{
		fclose(vid.stream);
		}
		
	curl_global_cleanup();


		
	return ret;
	}







DownloadThread::DownloadThread(wxWindow *pParent,wxString str_url, wxString str_file):
	 t_pParent(pParent),wstr_url(str_url),wstr_fname(str_file),wxThread(wxTHREAD_DETACHED)
	
	{
		
	
	downloadDone = false;





		if ( this->Create() != wxTHREAD_NO_ERROR )
	{
		wxLogError(wxT("Can't create download thread!"));
	}
	else
	{
		if ( this->Run() != wxTHREAD_NO_ERROR )
		{
			wxLogError(wxT("Can't start download thread!"));
		}
	}


	}

DownloadThread::~DownloadThread()
	{
	}

void *DownloadThread::Entry()
	{
	DownloadFile();
	return 0;
	

	}

void DownloadThread::OnExit()
	{
	}

void DownloadThread::CancelDownload()
	{
	t_pParent = NULL;
	downloadDone = false;
	}


void DownloadThread::DownloadFile()
	{

	libvdnEvent evt( wxEVT_DOWNLOAD, GetId() );
	evt.SetEventObject( (wxObject *)this->This() );
	evt.SetDownloadUrl(wstr_url);
	evt.SetDownloadFName( wstr_fname);
	evt.SetDownloadStatus(libvdnEvent::DOWNLOAD_RUNNING);
	evt.SetErrorCode(0); //initialize the error code value
	evt.SetDownloadedPercent(0);
	evt.SetParentWindow(t_pParent);


	int curlRetCode = libvdn_DownloadVideo(SER_YOUTUBE, (const char*)wstr_url.mb_str(wxConvUTF8), 
		(const char*)wstr_fname.mb_str(wxConvUTF8),evt,t_pParent );
	//function returns, download is hopefully done successfully 
	if(curlRetCode == 0 && downloadDone == false)
	{

	evt.SetDownloadStatus(libvdnEvent::DOWNLOAD_COMPLETE);
	downloadDone = true;
	if(t_pParent)
		{
		t_pParent->GetEventHandler()->AddPendingEvent(evt);
		}
	}
	else
	{


		if(t_pParent)
			{
		
			evt.SetDownloadStatus(libvdnEvent::DOWNLOAD_FAIL);
			evt.SetErrorCode(curlRetCode);
			t_pParent->GetEventHandler()->AddPendingEvent(evt);
			}
		}

	
	}




